Skip to main content

Golang Project Template

·3 mins

Golang Project Template #

tl;dr 🍴 the code and check it out: https://github.com/mikeblum/golang-project-template

Over the last year and change I’ve been writing lots of Golang to power a number of different tools and services. In other languages starting a new project can be as simple as rails new blog in Rails or Spring Initializr in the JVM Spring Boot world.

Golang, on the other hand, takes a much more hands-off approach as opposed to the more prescriptive frameworks of other langs. As far as I can tell it’s not a cardinal sin to copypasta code from one repo to another in Golang vs building out micro repos or common libraries - in fact it seems encouraged.

Groundhog Day With A Gopher #

When starting a new Golang project, there are a number of libraries I’ve encountered via either blogs or, most often, by reading the code of other golang projects and taking bardic inspiration from their work.

As with any new project - no matter how small the scope - I find myself copy and pasting the same New constructors and configs over and over again.

GOTO libraries 📚 #

At the moment I’ve coalesced around these awesome libraries - incidentally many of them made the awesome-go list!

pre-commit: https://pre-commit.com/

A framework for managing and maintaining multi-language pre-commit hooks.

A poor man’s CI/CD these hooks can run locally as well as in ☁️ CI/CD. There are many different linters (watch out for abandoned ones!) to cover everything from Dockerfiles to catching credentials and things best not committed to version control.

golangci-lint: https://golangci-lint.run/

Fast linters Runner for Go.

golangci-lint has become an invaluable mentor and made me a much better Gopher. Interestingly the linters only recently became compatible with Go 1.18 via this Github issue

logrus: https://github.com/sirupsen/logrus

Structured, pluggable logging for Go.

As of 1.19 Golang lacks an out-of-the-box structured logging library. Logrus has a stable API with flexible configuration that plays well locally as well as in the cloud with services like Datadog.

koanf: https://github.com/knadh/koanf

Simple, lightweight, extensible, configuration management library for Go.

An idiomatic 12-factor library for loading both custom conf files as well as interpolating environment variables. I frequently pair koanf with logrus to configure logging for local dev (colored plain-text) vs cloud deployments (json format).

testify: https://github.com/stretchr/testify

A toolkit with common assertions and mocks that plays nicely with the standard library.

While Golang’s stdlib import "testing" and TestHelloWorld(t *testing.T) are straight-forward I find the verbosity of sprinkling t into every assertion to be cumbersome. testify’s suite is an elegant API for setting up shared resources for package tests as well as tearing them down.

EDIT: After trying to do fuzzing and benchmarking, along with the unit and integration tests, I found myself fighting the suite flow (esp the lack of hooks in vsCode). Rather the structs in the stdlib have been much easier to work with after adopting the convention of t.Run: https://pkg.go.dev/testing

Resources #

Go By Example: an excellent resource for stdlib flows such as reading from a file, serializing http requests, or multi-threading with Go channels.

Golang Project Layout: there are a fair number of anti-patterns in this repo that don’t make sense. I’ve found this layout here to be much more ergonomic

Layout #

❌ top-level internal directory as this messes with test coverage. Similarly a top level pkg directory is silly in most situations. A good use of internal is for protobuf -generated code like this:

api/
  user/
    internal/
      user.pb.go
    user.go
    user_test.go
proto/
  user.proto

✅ domains for each top-level:

api/
  user/
    user.go
    user_test.go
cmd/
  app/
    app.go
  cli/
    cli.go
db/
  user/
    user.go
    user_test.go
web/
  html/
  js/

As a long time Java developer it took much restraint to stop tossing everything in a srcdirectory with com.bigcorp.proj style Go modules. 🤦